package cn.ydxlm.maplib;

import android.content.Context;
import android.util.Log;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.CoordinateConverter;
import com.amap.api.maps.model.LatLng;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeAddress;
import com.amap.api.services.geocoder.RegeocodeQuery;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.amap.api.services.poisearch.PoiSearch;
import cn.ydxlm.maplib.api.GetGeoCoderResultListener;
import cn.ydxlm.maplib.api.GetSuggestionResultListener;
import cn.ydxlm.maplib.api.LocationListener;
import cn.ydxlm.maplib.api.OnPoiSearchResultListener;
import cn.ydxlm.maplib.entity.Location;
import com.xujl.task.Emitter;
import com.xujl.task.RxExecutor;
import com.xujl.task.Task;

import java.util.LinkedList;
import java.util.List;

public class MapManager {
    private static final String TAG = "MapManager";
    private boolean isDebug = true;
    private List<LocationListener> mLocationListeners = new LinkedList<>();
    private List<GetSuggestionResultListener> mSuggestionResultListener = new LinkedList<>();
    private OnPoiSearchResultListener mPoiSearchResultListener;
    private GetGeoCoderResultListener mGetGeoCoderResultListener;
    private final Object mLock = new Object();
    //    private GeoCoder mCoder;
//    private SuggestionSearch mSuggestionSearch;
    private PoiSearch mPoiSearch;

    //声明mlocationClient对象
    public AMapLocationClient mlocationClient;
    //声明mLocationOption对象
    public AMapLocationClientOption mLocationOption = null;
    private Context mContext;

    private AMapLocationListener mAMapLocationListener = new AMapLocationListener() {
        @Override
        public void onLocationChanged (AMapLocation amapLocation) {
            if (amapLocation.getErrorCode() == 0) {
                //定位成功回调信息，设置相关消息
                amapLocation.getLocationType();//获取当前定位结果来源，如网络定位结果，详见定位类型表
                amapLocation.getLatitude();//获取纬度
                amapLocation.getLongitude();//获取经度
                amapLocation.getAccuracy();//获取精度信息
                //获取定位类型、定位错误返回码，具体信息可参照类参考中BDLocation类中的说明
                Location location = new Location(amapLocation.getLatitude(), amapLocation.getLongitude(),
                        amapLocation.getErrorCode(), amapLocation.getErrorInfo());
                location.setProvince(amapLocation.getProvince());
                location.setCity(amapLocation.getCity());
                location.setArea(amapLocation.getDistrict());
                location.setStreet(amapLocation.getStreet());
                location.setDirection(amapLocation.getBearing());
                location.setAdCode(amapLocation.getAdCode());
                log(location.toString());
                synchronized (mLock) {
                    for (LocationListener listener : mLocationListeners) {
                        if (listener == null) {
                            continue;
                        }
                        listener.onReceiveLocation(location);
                    }
                }
                stop();
            } else {
                //显示错误信息ErrCode是错误码，errInfo是错误信息，详见错误码表。
                log("location Error, ErrCode:"
                        + amapLocation.getErrorCode() + ", errInfo:"
                        + amapLocation.getErrorInfo());
            }
        }
    };

    public void setDebug (boolean debug) {
        isDebug = debug;
    }

    public void log (String msg) {
        if (!isDebug) {
            return;
        }
        Log.i(TAG, msg);
    }

    public void init (Context context) {
        mContext = context;
        mlocationClient = new AMapLocationClient(context);
//初始化定位参数
        mLocationOption = new AMapLocationClientOption();
//设置定位监听
        mlocationClient.setLocationListener(mAMapLocationListener);
//设置定位模式为高精度模式，Battery_Saving为低功耗模式，Device_Sensors是仅设备模式
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//设置定位间隔,单位毫秒,默认为2000ms
        mLocationOption.setInterval(2000);
        mLocationOption.setOnceLocation(true);
//设置定位参数
        mlocationClient.setLocationOption(mLocationOption);
    }


    public void startLocation () {
        RxExecutor.getInstance()
                .executeTask(new Task<Object>() {
                    @Override
                    public void run (Emitter emitter) throws Exception {
                        super.run(emitter);
//                        if (isConfig) {
//                            mLocationClient.start();
//                            return;
//                        }
//                        isConfig = true;

                        //启动定位
                        mlocationClient.startLocation();
                    }
                });
    }

    public void stop () {
        mlocationClient.stopLocation();
    }

    public void addLocationListener (LocationListener locationListener) {
        synchronized (mLock) {
            mLocationListeners.add(locationListener);
        }
    }


    public void removeLocationListener (LocationListener locationListener) {
        synchronized (mLock) {
            mLocationListeners.add(locationListener);
        }
    }

    public void suggestionSearch (String city, String keyword) {
        PoiSearch.Query query = new PoiSearch.Query(keyword, "", city);
        //keyWord表示搜索字符串，
        //第二个参数表示POI搜索类型，二者选填其一，选用POI搜索类型时建议填写类型代码，码表可以参考下方（而非文字）
        //cityCode表示POI搜索区域，可以是城市编码也可以是城市名称，也可以传空字符串，空字符串代表全国在全国范围内进行搜索
        query.setPageSize(20);// 设置每页最多返回多少条poiitem
        query.setPageNum(1);//设置查询页码
        query.setCityLimit(true);
        mPoiSearch = new PoiSearch(mContext, query);
        mPoiSearch.setOnPoiSearchListener(new GetSuggestionResultListener() {
            @Override
            public void onSuggestionResult (List<Location> list) {
                for (GetSuggestionResultListener listener : mSuggestionResultListener) {
                    listener.onSuggestionResult(list);
                }
            }
        });
        mPoiSearch.searchPOIAsyn();
    }

    public void addSuggestionResultListener (GetSuggestionResultListener suggestionResultListener) {
        if (suggestionResultListener == null || mSuggestionResultListener.contains(suggestionResultListener)) {
            return;
        }
        mSuggestionResultListener.add(suggestionResultListener);
    }

    public void removeSuggestionResultListener (GetSuggestionResultListener suggestionResultListener) {
        if (suggestionResultListener == null) {
            return;
        }
        mSuggestionResultListener.remove(suggestionResultListener);
    }

    /**
     * 逆地理编码
     */
    public void geoCoderByReverse (double lat, double lon) {
        LatLonPoint point = new LatLonPoint(lat, lon);
        GeocodeSearch geocodeSearch = new GeocodeSearch(mContext);
        RegeocodeQuery regeocodeQuery = new RegeocodeQuery(point, 500, GeocodeSearch.AMAP);
        geocodeSearch.getFromLocationAsyn(regeocodeQuery);
        geocodeSearch.setOnGeocodeSearchListener(mGetGeoCoderResultListener);
    }

    public void setPoiSearchResultListener (OnPoiSearchResultListener poiSearchResultListener) {
        mPoiSearchResultListener = poiSearchResultListener;
    }

    public void setGetGeoCoderResultListener (GetGeoCoderResultListener getGeoCoderResultListener) {
        mGetGeoCoderResultListener = getGeoCoderResultListener;
    }

    public void poiSearch (String city, String keywords, int page) {
        poiSearch(city, keywords, null, page);
    }

    public void poiSearch (String city, String keywords, String tag, int page) {
        PoiSearch.Query query = new PoiSearch.Query(keywords, "", city);
        //keyWord表示搜索字符串，
        //第二个参数表示POI搜索类型，二者选填其一，选用POI搜索类型时建议填写类型代码，码表可以参考下方（而非文字）
        //cityCode表示POI搜索区域，可以是城市编码也可以是城市名称，也可以传空字符串，空字符串代表全国在全国范围内进行搜索
        query.setPageSize(page);// 设置每页最多返回多少条poiitem
        query.setCityLimit(true);
        query.setPageNum(1);//设置查询页码
        mPoiSearch = new PoiSearch(mContext, query);
        mPoiSearch.setOnPoiSearchListener(mPoiSearchResultListener);
        mPoiSearch.searchPOIAsyn();
    }

    public void poiSearchNear (double lat, double lon, final String keywords, int page) {
        final LatLonPoint point = new LatLonPoint(lat, lon);
        GeocodeSearch geocodeSearch = new GeocodeSearch(mContext);
        RegeocodeQuery regeocodeQuery = new RegeocodeQuery(point, 500, GeocodeSearch.AMAP);
        geocodeSearch.getFromLocationAsyn(regeocodeQuery);
        geocodeSearch.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener() {
            @Override
            public void onRegeocodeSearched (RegeocodeResult regeocodeResult, int i) {
                RegeocodeAddress address = regeocodeResult.getRegeocodeAddress();
                PoiSearch.Query query = new PoiSearch.Query(keywords, "", address.getCity());
                query.setLocation(point);
                //keyWord表示搜索字符串，
                //第二个参数表示POI搜索类型，二者选填其一，选用POI搜索类型时建议填写类型代码，码表可以参考下方（而非文字）
                //cityCode表示POI搜索区域，可以是城市编码也可以是城市名称，也可以传空字符串，空字符串代表全国在全国范围内进行搜索
                query.setPageSize(20);// 设置每页最多返回多少条poiitem
                query.setCityLimit(true);
                query.setPageNum(1);//设置查询页码
                final Location location = new Location();
                location.setProvince(address.getProvince());
                location.setCity(address.getCity());
                location.setArea(address.getDistrict());
                mPoiSearchResultListener.setSearchLocation(location);
                mPoiSearch = new PoiSearch(mContext, query);
                mPoiSearch.setBound(new PoiSearch.SearchBound(point, 1000));//设置周边搜索的中心点以及半径
                mPoiSearch.setOnPoiSearchListener(mPoiSearchResultListener);
                mPoiSearch.searchPOIAsyn();
            }

            @Override
            public void onGeocodeSearched (GeocodeResult geocodeResult, int i) {

            }
        });


    }

    public Context getContext () {
        return mContext;
    }

    public static double[] bd2GaoDe (double lat, double lon) {
        CoordinateConverter converter = new CoordinateConverter(getInstance().getContext());
        // CoordType.GPS 待转换坐标类型
        converter.from(CoordinateConverter.CoordType.BAIDU);
        // sourceLatLng待转换坐标点 LatLng类型
        converter.coord(new LatLng(lat, lon));
        // 执行转换操作
        LatLng desLatLng = converter.convert();
        return new double[]{desLatLng.latitude, desLatLng.longitude};
    }

    public void recyclePoiSearch () {
        if (mPoiSearch != null) {
            mPoiSearch = null;
            setPoiSearchResultListener(null);
        }
    }

    public void recycleGeoCoder () {
//        if (mCoder != null) {
//            mCoder.destroy();
//            mCoder = null;
//            setGetGeoCoderResultListener(null);
//        }
    }

    public static MapManager getInstance () {
        return Holder.ourInstance;
    }

    private MapManager () {
    }

    private static class Holder {
        private static final MapManager ourInstance = new MapManager();
    }
}
